import sys

from PySide2.QtWidgets import *
from PySide2.QtCore import Qt, QSize
from PySide2.QtGui import QFont

from config_win import ConfigWgt
from test_win import TestWgt
from deploy_win import DeployWgt
from CustStyleSheets import *
from CustWidgets import HArrowLabel
from CustWidgets import Flag, LogConsole, LogUpdateThread


class MainWin(QWidget):

    def __init__(self, parent=None, root_win=None, welcome_win=None, 
        eii_home="", data_stream_name="", pwd="", show_all=True, current_win="config"):
        super(MainWin, self).__init__(parent=parent)
        # For next and prev buttons tracking
        # Value ranges: config, test, deploy
        self.current_win = current_win

        self.root_win = root_win
        self.welcome_win = welcome_win
        self.eii_home = eii_home
        self.project_name = data_stream_name
        self.host_pwd = pwd
        # Control the deploy-window
        self.show_all = show_all

        self.init_log_console()
        self.init_ui()
        self.signals_collector()

    def init_ui(self):
        self.grid_lyt_global = QGridLayout(self)
        
        self.init_top()
        self.init_central()
        self.init_bottom()

    def init_top(self):
        self.wgt_top = QWidget(self)
        self.grid_lyt_top = QGridLayout(self.wgt_top)
        self.grid_lyt_top.setContentsMargins(0, 0, 0, 0)

        self.lbl_config = QLabel(self.wgt_top)
        self.lbl_config.setText("Config")
        self.lbl_config.setMinimumSize(QSize(80, 40))
        self.lbl_config.setStyleSheet(SS_LBL_ACTIVATED)
        self.lbl_config.setAlignment(Qt.AlignCenter)
        self.grid_lyt_top.addWidget(self.lbl_config, 0, 2, 1, 1)

        self.lbl_test = QLabel(self.wgt_top)
        self.lbl_test.setText("Test")
        self.lbl_test.setMinimumSize(QSize(80, 40))
        self.lbl_test.setStyleSheet(SS_LBL_DEACTIVATED)
        self.lbl_test.setAlignment(Qt.AlignCenter)
        self.grid_lyt_top.addWidget(self.lbl_test, 0, 4, 1, 1)

        self.lbl_deploy = QLabel(self.wgt_top)
        self.lbl_deploy.setText("Deploy")
        self.lbl_deploy.setMinimumSize(QSize(80, 40))
        self.lbl_deploy.setStyleSheet(SS_LBL_DEACTIVATED)
        self.lbl_deploy.setAlignment(Qt.AlignCenter)
        self.grid_lyt_top.addWidget(self.lbl_deploy, 0, 6, 1, 1)

        self.btn_home = QPushButton(self.wgt_top)
        self.btn_home.setText("&Home")
        self.btn_home.setMinimumSize(QSize(70, 0))
        self.btn_home.setMaximumSize(QSize(70, 16777215))
        self.btn_home.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_top.addWidget(self.btn_home, 0, 8, 1, 1)

        self.lbl_arrow1 = HArrowLabel(self.wgt_top)
        self.lbl_arrow1.setMinimumSize(QSize(50, 0))
        self.lbl_arrow1.setMaximumSize(QSize(50, 16777215))
        self.grid_lyt_top.addWidget(self.lbl_arrow1, 0, 3, 1, 1)
        
        self.lbl_arrow2 = HArrowLabel(self.wgt_top)
        self.lbl_arrow2.setMinimumSize(QSize(50, 0))
        self.lbl_arrow2.setMaximumSize(QSize(50, 16777215))
        self.grid_lyt_top.addWidget(self.lbl_arrow2, 0, 5, 1, 1)

        # Placeholder for better layout
        btn_ph = QPushButton(self.wgt_top)
        btn_ph.setMinimumSize(QSize(70, 0))
        btn_ph.setMaximumSize(QSize(70, 16777215))
        btn_ph.setText("")
        btn_ph.setStyleSheet("border: none;")
        self.grid_lyt_top.addWidget(btn_ph, 0, 0, 1, 1)

        spacer1 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.grid_lyt_top.addItem(spacer1, 0, 7, 1, 1)
        spacer2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.grid_lyt_top.addItem(spacer2, 0, 1, 1, 1)

        self.grid_lyt_global.addWidget(self.wgt_top, 0, 0, 1, 1)

    def init_bottom(self):
        self.wgt_bottom = QWidget(self)
        self.grid_lyt_bottom = QGridLayout(self.wgt_bottom)
        self.grid_lyt_bottom.setContentsMargins(0, 0, 0, 0)
        
        self.btn_prev = QPushButton(self.wgt_bottom)
        self.btn_prev.setText("<&Prev")
        self.btn_prev.setMinimumSize(QSize(70, 0))
        self.btn_prev.setMaximumSize(QSize(70, 16777215))
        self.btn_prev.setStyleSheet(SS_MINI_BTN_DISABLE)
        self.grid_lyt_bottom.addWidget(self.btn_prev, 0, 1, 1, 1)
        if not self.show_all:
            self.btn_prev.hide()

        self.btn_next = QPushButton(self.wgt_bottom)
        self.btn_next.setText("&Next>")
        self.btn_next.setMinimumSize(QSize(70, 0))
        self.btn_next.setMaximumSize(QSize(70, 16777215))
        self.btn_next.setStyleSheet(SS_MINI_BTN_ENABLE)
        self.grid_lyt_bottom.addWidget(self.btn_next, 0, 2, 1, 1)
        if not self.show_all:
            self.btn_next.hide()
        
        spacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
        self.grid_lyt_bottom.addItem(spacer, 0, 0, 1, 1)

        self.grid_lyt_global.addWidget(self.wgt_bottom, 4, 0, 1, 1)

    def init_central(self):
        self.wgt_config = ConfigWgt(
            eii_home=self.eii_home, 
            project_name=self.project_name,
            host_pwd=self.host_pwd
        )
        self.wgt_test = TestWgt(
            root_win=self.root_win,
            log_console=self._log_console,
            log_proc_flag=self._log_proc_flag,
            eii_home=self.eii_home, 
            project_name=self.project_name,
            pwd=self.host_pwd,
        )
        self.wgt_deploy = DeployWgt(
            root_win=self.root_win,
            log_console=self._log_console,
            log_proc_flag=self._log_proc_flag,
            eii_home=self.eii_home, 
            project_name=self.project_name,
            show_all=self.show_all,
            pwd=self.host_pwd,
        )
        self.wgt_config.show()
        self.wgt_test.hide()
        self.wgt_deploy.hide()

        self.grid_lyt_global.addWidget(self.wgt_config, 1, 0, 1, 1)
        self.grid_lyt_global.addWidget(self.wgt_test, 2, 0, 1, 1)
        self.grid_lyt_global.addWidget(self.wgt_deploy, 3, 0, 1, 1)
    
    def init_log_console(self):
        # Create a log console
        self._log_console = LogConsole()
        self._log_console.setWindowTitle("Log Console")
        self._log_console.resize(self.root_win.size().width(), 200)
        self._log_console.move(self.root_win.x(), self.root_win.y() + self.root_win.size().height())
        self._log_console.hide()

        # Flags for helping to redirect stdout and stderr to log console
        self._log_proc_flag = Flag(init_val=None)
        self._log_text_line = Flag(init_val="")

        # Working thread for updating texts to log console
        self._log_update_thread = LogUpdateThread(self._log_text_line, [])
    
    def slot_btn_home(self):
        if self.current_win == "config":
            # No log window for config-window
            pass
        elif self.current_win == "test":
            self.wgt_test.slot_btn_home()
        elif self.current_win == "deploy":
            self.wgt_deploy.slot_btn_home()
        self.close()
        self.welcome_win.show()

    def slot_btn_prev(self):
        if self.current_win == "config":
            # No window before config-window
            pass
        elif self.current_win == "test":
            self.wgt_test.slot_btn_prev()

            self.wgt_test.hide()
            self.wgt_deploy.hide()
            # Update bottom buttons' status
            self.btn_prev.setStyleSheet(SS_MINI_BTN_DISABLE)
            self.btn_next.setStyleSheet(SS_MINI_BTN_ENABLE)
            # Update top labels' status
            self.lbl_config.setStyleSheet(SS_LBL_ACTIVATED)
            self.lbl_test.setStyleSheet(SS_LBL_DEACTIVATED)
            self.lbl_deploy.setStyleSheet(SS_LBL_DEACTIVATED)
            # Update window's tracker
            self.current_win = "config"

            # When go back from "test" to "config", need to refresh Config Win
            self.grid_lyt_global.removeWidget(self.wgt_config)
            self.wgt_config.deleteLater()
            self.wgt_config = ConfigWgt(
                eii_home=self.eii_home, 
                project_name=self.project_name,
                host_pwd=self.host_pwd
            )
            self.grid_lyt_global.addWidget(self.wgt_config, 1, 0, 1, 1)
            self.wgt_config.show()
        
        elif self.current_win == "deploy":
            self.wgt_deploy.slot_btn_prev()

            self.wgt_config.hide()
            self.wgt_deploy.hide()
            self.wgt_test.show()
            # Update bottom buttons' status
            self.btn_prev.setStyleSheet(SS_MINI_BTN_ENABLE)
            self.btn_next.setStyleSheet(SS_MINI_BTN_ENABLE)
            # Update top labels' status
            self.lbl_config.setStyleSheet(SS_LBL_DEACTIVATED)
            self.lbl_test.setStyleSheet(SS_LBL_ACTIVATED)
            self.lbl_deploy.setStyleSheet(SS_LBL_DEACTIVATED)
            # Update window's tracker
            self.current_win = "test"
    
    def slot_btn_next(self):
        if self.current_win == "config":
            # Get module config
            complete_config = self.wgt_config.slot_config_next()
            if not complete_config:
                return
            
            self.wgt_config.hide()
            self.wgt_deploy.hide()
            self.wgt_test.set_config(complete_config)
            self.wgt_test.show()
            # Update bottom buttons' status
            self.btn_prev.setStyleSheet(SS_MINI_BTN_ENABLE)
            self.btn_next.setStyleSheet(SS_MINI_BTN_ENABLE)
            # Update top labels' status
            self.lbl_config.setStyleSheet(SS_LBL_DEACTIVATED)
            self.lbl_test.setStyleSheet(SS_LBL_ACTIVATED)
            self.lbl_deploy.setStyleSheet(SS_LBL_DEACTIVATED)
            # Update window's tracker
            self.current_win = "test"

        elif self.current_win == "test":
            res = QMessageBox.information(self, "Confirmation", 
                "Please make sure you have test out the data stream pipeline.\nAnd stop services before move to next steps or close window", 
                QMessageBox.Cancel, QMessageBox.Ok)
            if res == QMessageBox.Cancel:
                return

            self.wgt_test.slot_btn_next()

            self.wgt_config.hide()
            self.wgt_test.hide()
            self.wgt_deploy.show()
            # Update bottom buttons' status
            self.btn_prev.setStyleSheet(SS_MINI_BTN_ENABLE)
            self.btn_next.setStyleSheet(SS_MINI_BTN_DISABLE)
            # Update top labels' status
            self.lbl_config.setStyleSheet(SS_LBL_DEACTIVATED)
            self.lbl_test.setStyleSheet(SS_LBL_DEACTIVATED)
            self.lbl_deploy.setStyleSheet(SS_LBL_ACTIVATED)
            # Update window's tracker
            self.current_win = "deploy"
        
        elif self.current_win == "deploy":
            # No window after deploy-window
            pass
    
    def slot_log_console_update(self):
        if self._log_proc_flag.t:
            if self._log_update_thread.proc:
                if not self._log_update_thread.stopped:
                    self._log_update_thread.stop()
                self._log_update_thread = LogUpdateThread(self._log_text_line, [])
            self._log_update_thread.proc = self._log_proc_flag.t
            self._log_update_thread.start()

    def signals_collector(self):
        # When log process's id changed, generate a new thread to update the new one
        self._log_proc_flag.valueChanged.connect(self.slot_log_console_update)
        self._log_text_line.valueChanged.connect(self._log_console.insert_text)

        self.btn_home.clicked.connect(self.slot_btn_home)
        self.btn_prev.clicked.connect(self.slot_btn_prev)
        self.btn_next.clicked.connect(self.slot_btn_next)
    
